package com.avocado.actor;

import com.avocado.constant.ActorConstant;
import com.avocado.dispatcher.ActorDispatcher;
import com.avocado.mailBox.MailBox;
import com.avocado.message.Message;
import com.avocado.stats.ActorStats;
import lombok.Getter;
import lombok.Setter;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @author avocado
 * @date 2023/5/28 22:10
 */
@Getter
@Setter
public abstract class AbstractActor implements Actor {

    private long id;

    private long groupId;

    private MailBox mailBox;

    private ActorStats actorStats;

    private ActorDispatcher actorDispatcher;

    private volatile boolean isDispatch;

    protected ReentrantLock lock = new ReentrantLock();

    public abstract void receive(Message message);

    public boolean tell(Message message) {
        lock.lock();
        try {
            mailBox.offer(message);
            if (!isDispatch) {
                actorDispatcher.dispatch(this);
                isDispatch = true;
            }
        } finally {
            lock.unlock();
        }
        return true;
    }

    public boolean isActive() {
        return actorStats.getStats() == ActorConstant.active;
    }

    public void active() {
        actorStats.setStats(ActorConstant.active);
    }

    public void deactive() {
        actorStats.setStats(ActorConstant.deactive);
    }

    public final void worker() {
        try {
            Message message = pollMessage();
            if (message != null) {
                receive(message);
            }
        } catch (Exception e) {
            // 奔溃自恢复
            e.printStackTrace();
        } finally {
            if (hasMessage()) {
                actorDispatcher.dispatch(this);
                isDispatch = true;
            } else {
                isDispatch = false;
            }
        }

    }

    protected Message pollMessage() {
        lock.lock();
        try {
            return mailBox.poll();
        } finally {
            lock.unlock();
        }
    }

    protected boolean hasMessage() {
        return mailBox.size() > 0;
    }

    protected void clearMailBox() {
        lock.lock();
        try {
            mailBox.clear();
        } finally {
            lock.unlock();
        }
    }

}
